/*
 * rotvalve.c
 *
 *  Created on: May 19, 2021
 *      Author: soliber
 *      说明：	旋转阀API
 *      注意：	手册中的波特率不对，正确的波特率为9600
 */

#include "../RotValve/rotvalve.h"

#include "usart.h"
#include "string.h"

//使用的通信串口
#define huartx huart3

/*
 * 	指令								B0   B1   B2   B3   B4   B5   B6   B7
 * 								 		对象 命令 速度 方向   坐标    光耦 预留
 */
#define CMD_SIZE	8
const uint8_t CMD_CONNECT[] =			{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
const uint8_t CMD_SET_HOLE[] =			{0x03,0x66,0x00,0x00,0x00,0x00,0x00,0x00};
const uint8_t CMD_GET_HOLE_CURRENT[] =	{0x03,0x33,0x00,0x00,0x00,0x00,0x00,0x00};
const uint8_t CMD_GET_HOLE_MEMORY[]  =	{0x01,0x09,0x00,0x01,0x00,0x00,0x00,0x00};
//状态位
#define STATUS_AT_HOLE1			0x00	//在1号孔位
#define STATUS_NOT_AT_HOLE1		0x01	//在非1号孔位
#define STATUS_MALPOSITION		0x02	//需要回零位，错位
#define STATUS_POWERDOWN		0x2A	//需要回零位，上次操作在运动过程中断电，未运行到目标孔位


/*---------------------API实现-----------------------*/
/*
 * 函数名：	HAL_RotValve_Init
 *
 * 说明：	初始化旋转阀
 * 			联机并设置默认孔位
 *
 * 参数：	hole，默认孔位
 *
 * 返回值：	操作状态
 * 			HAL_OK，操作成功，并旋转到默认孔位
 * 			HAL_TIMEOUT，超时，旋转阀无响应
 * 			HAL_ERROR，操作中发生了错误
 */
HAL_StatusTypeDef HAL_RotValve_Init(RotValve_Hole_Typedef hole)
{
	HAL_StatusTypeDef st;
	uint8_t retbuf[CMD_SIZE];

	//发送联机指令
	st = HAL_UART_Transmit(&huartx, CMD_CONNECT, CMD_SIZE, 1000);
	if(st != HAL_OK)
	{
		//错误：发送失败
		return HAL_ERROR;
	}

	//接收返回值
	st = HAL_UART_Receive(&huartx, retbuf, CMD_SIZE, 1000);
	if(st == HAL_TIMEOUT)
	{
		//接收超时
		return HAL_TIMEOUT;
	}
	else if(st != HAL_OK)
	{
		//错误：接收错误
		return HAL_ERROR;
	}

	printf("旋转阀联机成功，版本：20%2x年%2x月%2x日\r\n",retbuf[4],retbuf[5],retbuf[6]);

	//设置到默认孔位
	st = HAL_RotValve_Set(hole);
	if(st != HAL_OK)
	{
		//错误：发送失败
		return HAL_ERROR;
	}

	return HAL_OK;

}

/*
 * 函数名：	HAL_RotValve_Set
 *
 * 说明：	设置孔位
 *
 * 参数：	hole，目标孔位
 *
 * 返回值：	操作状态
 * 			HAL_OK，操作成功，并旋转到目标孔位
 * 			HAL_TIMEOUT，超时，旋转阀无响应
 * 			HAL_ERROR，响应错误或位置错误
 */
HAL_StatusTypeDef HAL_RotValve_Set(RotValve_Hole_Typedef hole)
{
	HAL_StatusTypeDef st;
	uint8_t txbuf[CMD_SIZE];
	uint8_t retbuf[CMD_SIZE];

	//封装成帧
	memcpy(txbuf,CMD_SET_HOLE,8);
	txbuf[5]=hole;

	//发送设置孔位指令
	st = HAL_UART_Transmit(&huartx, txbuf, CMD_SIZE, 1000);
	if(st != HAL_OK)
	{
		//错误：发送失败
		return HAL_ERROR;
	}

	//接收返回值
	st = HAL_UART_Receive(&huartx, retbuf, CMD_SIZE, 1000);
	if(st == HAL_TIMEOUT)
	{
		//接收超时
		return HAL_TIMEOUT;
	}
	else if(st != HAL_OK)
	{
		//错误：接收错误
		return HAL_ERROR;
	}

	//验证返回值

	//返回值的B0~B1应与发送的指令相同
	if(memcmp(CMD_SET_HOLE,retbuf,2))
	{
		//错误：返回值错误
		return HAL_ERROR;
	}

	//状态位应与当前孔位对应
	if(retbuf[6]!=((retbuf[5]==HOLE1)?STATUS_AT_HOLE1:STATUS_NOT_AT_HOLE1))
	{
		//错误：状态错误
		return HAL_ERROR;
	}

	//返回的孔位应与目标孔位对应
	if(retbuf[5]!=hole)
	{
		//错误：位置错误
		return HAL_ERROR;
	}

	return HAL_OK;

}

/*
 * 函数名：	HAL_RotValve_Get
 *
 * 说明：	查询当前孔位
 * 			手册提示应在设置孔位至少5s后查询
 *
 * 参数：	无
 *
 * 返回值：	操作状态
 * 			HAL_OK，操作成功
 * 			HAL_TIMEOUT，超时，旋转阀无响应
 * 			HAL_ERROR，发生了错误
 */
HAL_StatusTypeDef HAL_RotValve_Get(RotValve_Hole_Typedef* hole)
{
	HAL_StatusTypeDef st;
	uint8_t retbuf[CMD_SIZE];

	//发送查询孔位指令
	st = HAL_UART_Transmit(&huartx, CMD_GET_HOLE_CURRENT, CMD_SIZE, 1000);
	if(st != HAL_OK)
	{
		//错误：发送失败
		return HAL_ERROR;
	}

	//接收返回值
	st = HAL_UART_Receive(&huartx, retbuf, CMD_SIZE, 5000);
	if(st == HAL_TIMEOUT)
	{
		//接收超时
		return HAL_TIMEOUT;
	}
	else if(st != HAL_OK)
	{
		//错误：接收错误
		return HAL_ERROR;
	}

	//验证返回值

	//返回值的B0~B1应与发送的指令相同
	if(memcmp(CMD_GET_HOLE_CURRENT,retbuf,2))
	{
		//错误：返回值错误
		return HAL_ERROR;
	}

	//状态位应与当前孔位对应
	if(retbuf[6]!=((retbuf[5]==HOLE1)?STATUS_AT_HOLE1:STATUS_NOT_AT_HOLE1))
	{
		//错误：状态错误
		return HAL_ERROR;
	}

	//返回值验证正确，传参
	*hole = retbuf[5];

	return HAL_OK;

}
